#pragma once
#include <string>
#include <map>
#include <set>
#include <vector>
#include <list>
#include <iostream>
using namespace std;
typedef string symInfo;
//for temporary save the code info
struct code {
    string codeLine;
    set<symInfo> use , def; 
    list<int> outEdge , inEdge;
    vector<symInfo> syms;
    string jumpLabel;
    int lineno;
};

class phiFunction :public code{
    public:
	symInfo symAbout;
	phiFunction(symInfo a , int count)
	{
	    use.insert(a);
	    def.insert(a);
	    symAbout = a;
	    for (int i = 0 ; i != count ; ++i)
	    {
		syms.push_back(a);
	    }
	    renameCount = 0;
	}
	void rename(int index);
    private:
	int renameCount;
};

class CFG_Node {
public:
    friend class CFG;
    typedef list<CFG_Node*> edgeList;

    CFG_Node()
    {
	dominImm = NULL;
    }
    //member function for map
    //Add a line to the code block
    int addCode(code &c); 
    //Add the outEdge of the node
    void addOutEdge(CFG_Node *next);
    void addInEdge(CFG_Node *prev);

    //List all the node in edge
    edgeList gIn();
    edgeList gOut();

    bool isDef(symInfo sym);
    bool isUse(symInfo sym);
    bool hasLine(int lineno);

    CFG_Node* dominImm;  //The node's immedite dominator
    list<CFG_Node*> dominTreeChild;
    //member function for SSA
    void insertPhiFunction(symInfo sym);
    int findPhiFunction(symInfo sym);
    void renameVar(symInfo sym , int baseVarIndex , int &varCount);
    void computeDomin();
    void computeDF();

    int CFGid;
    //return a string contains all the code in dot form
    string getDotDescribe(); 
    vector<code> codes;
    set<CFG_Node*> dominSet , DF;
private:
    edgeList outEdge , inEdge;
    vector<phiFunction> phiFuncs;
};

class CFG {
    public:
	//Initialize
	CFG();
	typedef vector<CFG_Node> CFGNodeVec_t;
	//set
	void addNode(CFG_Node T);
	//get
	CFG_Node &getNode(int index) {return nodeVec[index];}
	void linkNode(int start , int end);
	//For range loop
	CFGNodeVec_t::iterator begin() {return nodeVec.begin();}
	CFGNodeVec_t::iterator end()   {return nodeVec.end();}
	//computeDF
	void computeDF();
	//computeDomin
	void computeDomin();
	//SSA
	void ssa();
	//Print Status
	void printCFG(ostream &os);
    private:
	CFGNodeVec_t nodeVec;
	//Calcuate the root
	int root();
	//Symbol user in this code
	set<symInfo> symTable;
};

extern vector<code> codeTable;
extern map<string , int> symTable;
extern map<string , int> labelTable;
//For debug
//Print the code info decode from the source file
int printStatus();
void generateCFG();
